/**
 * 
 */
package it.unical.canonaco.rende.igpe.game.cbv.guilayer.components;

import it.unical.canonaco.rende.igpe.game.cbv.guilayer.sprites.LinkedSpriteSheet;
import it.unical.canonaco.rende.igpe.game.cbv.guilayer.sprites.Sprite;
import it.unical.canonaco.rende.igpe.game.cbv.guilayer.sprites.SpriteSheetCache;
import it.unical.canonaco.rende.igpe.game.cbv.guilayer.sprites.UniqueSpriteSheet;
import it.unical.canonaco.rende.igpe.game.cbv.guilayer.sprites.key.AvatarFrameKey;
import it.unical.canonaco.rende.igpe.game.cbv.guilayer.sprites.key.PawnSheetKey;
import it.unical.canonaco.rende.igpe.game.cbv.guilayer.sprites.key.TextureFrameKey;
import it.unical.canonaco.rende.igpe.game.cbv.guilayer.sprites.key.TexturesSheetKey;
import it.unical.canonaco.rende.igpe.game.cbv.logiclayer.engine.component.pawn.GenericPawn;
import it.unical.canonaco.rende.igpe.game.cbv.logiclayer.engine.component.world.Chessboard;
import it.unical.canonaco.rende.igpe.game.cbv.logiclayer.engine.component.world.TextureInfoBean;
import it.unical.canonaco.rende.igpe.game.cbv.logiclayer.engine.events.EventManager;
import it.unical.canonaco.rende.igpe.game.cbv.logiclayer.engine.events.GenericEvent;
import it.unical.canonaco.rende.igpe.game.cbv.logiclayer.engine.events.InvalidPointSettingEvent;
import it.unical.canonaco.rende.igpe.game.cbv.logiclayer.engine.events.StartingPositionEvent;
import it.unical.canonaco.rende.igpe.game.cbv.logiclayer.engine.exceptions.InvalidFileException;

import java.awt.AlphaComposite;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.Point;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Map;

import javax.imageio.ImageIO;

/**
 * @author Massimo Canonaco
 *
 */
public class OrthogonalPrePlayMatchPainterManager extends AbstractPainterManager {

	/** */
	private PawnSheetKey pawnKey;
	
	/** */
	private AvatarFrameKey puppetMapKey;
	
	/** */
	private TexturesSheetKey textureSheetKey;
	
	/** */
	private TextureFrameKey singleTextureKey;
	
	/** */
	private TexturesSheetKey overallTextureKey;
	
	/** */
	private TextureFrameKey spawnareaKey;
	
	/** */
	private TextureFrameKey nopeKey;
	
	private LinkedList<Point> nopePoints;
	
	/** */
	private Map<GenericPawn,StartingPointGenericPawnsSubjectsInformations> eventSubjects;

	/** */
	public OrthogonalPrePlayMatchPainterManager(SpriteSheetCache spriteCache, final String spawnTexturePath, final String texturePath, final String errorImgPath, it.unical.canonaco.rende.igpe.game.cbv.logiclayer.engine.component.world.Map map)
	{
		super(spriteCache, texturePath, errorImgPath);

		textureSheetKey = new TexturesSheetKey();
		textureSheetKey.setMapName(map.getName());
		
		singleTextureKey = new TextureFrameKey();
		textureSheetKey.setFrameKey(singleTextureKey);
		
		Collection<TextureInfoBean> textureCollection = map.getTextures().values();
		LinkedSpriteSheet lss = new LinkedSpriteSheet();
		try 
		{
			for (TextureInfoBean textureBean : textureCollection) 
			{
				singleTextureKey.setTextureID(textureBean.getAcutalKey());
				Sprite sprite = new Sprite();
				sprite.setFrameName(String.valueOf(textureBean.getAcutalKey()));
				lss.addFrame(sprite);
				lss.setImage(ImageIO.read(new FileInputStream(textureFolder+textureBean.getName()+"."+textureBean.getExtension())));
			}
			spritesCache.add(textureSheetKey, lss);
			LinkedSpriteSheet overallTexture = new LinkedSpriteSheet();
			overallTextureKey = new TexturesSheetKey();
			overallTextureKey.setMapName("overall");
			nopeKey = new TextureFrameKey();
			spawnareaKey = new TextureFrameKey();

			overallTextureKey.setFrameKey(spawnareaKey);
			spawnareaKey.setTextureID(0);
			Sprite sprite = new Sprite();
			sprite.setFrameName("0");
			overallTexture.addFrame(sprite);
			overallTexture.setImage(ImageIO.read(new FileInputStream(spawnTexturePath)));

			overallTextureKey.setFrameKey(nopeKey);
			nopeKey.setTextureID(1);
			sprite = new Sprite();
			sprite.setFrameName("1");
			overallTexture.addFrame(sprite);
			overallTexture.setImage(ImageIO.read(new FileInputStream(errorImgPath)));

			spritesCache.add(overallTextureKey, overallTexture);
		
		}catch (IOException e) 
		{
				e.printStackTrace();
		}
		pawnKey = new PawnSheetKey();
		pawnKey.setWhat(PawnSheetKey.FRAME_TYPE_AVATAR);
		pawnKey.setWhen("");
		
		puppetMapKey = new AvatarFrameKey();
		puppetMapKey.setKey(AvatarFrameKey.PUPPET_MAP);
		pawnKey.setFrameKey(puppetMapKey);
		
		eventSubjects = new HashMap<>();
		nopePoints = new LinkedList<>();
	}
	/* (non-Javadoc)
	 * @see it.unical.canonaco.rende.igpe.game.cbv.logiclayer.engine.events.EventListener#notify(it.unical.canonaco.rende.igpe.game.cbv.logiclayer.engine.events.GenericEvent)
	 */
	@Override
	public void notify(GenericEvent event) 
	{
		final float EVENT_GUID = event.getGUID();
		
		if(EVENT_GUID == StartingPositionEvent.GUID)
		{
			if(!nopePoints.isEmpty())
			{
				nopePoints.clear();
			}
			StartingPositionEvent startingEvent = (StartingPositionEvent) event;
			StartingPointGenericPawnsSubjectsInformations temp = new StartingPointGenericPawnsSubjectsInformations();
			if(startingEvent.isAdd())
			{
				temp.add = true;
				temp.opacity = 0;
			}
			else
			{
				temp.add = false;
				temp.opacity = 100;
				temp.eventPoint = new Point(startingEvent.getRowCell(),startingEvent.getColumnCell());
			}
			temp.pawn = startingEvent.getSubject();
			eventSubjects.put(temp.pawn, temp);
		}
		else if(EVENT_GUID == InvalidPointSettingEvent.GUID)
		{
			InvalidPointSettingEvent invalidEvent = (InvalidPointSettingEvent) event;
			overallTextureKey.setFrameKey(nopeKey);
			nopePoints.add(new Point(invalidEvent.getRow(),invalidEvent.getColumn()));
		}

	}

	/* (non-Javadoc)
	 * @see it.unical.canonaco.rende.igpe.game.cbv.guilayer.components.AbstractPainterManager#paintPawn(it.unical.canonaco.rende.igpe.game.cbv.logiclayer.engine.component.pawn.GenericPawn, int, java.awt.Graphics)
	 */
	@Override
	public void paintPawn(GenericPawn pawn, int tile, Graphics2D graphics) throws InvalidFileException 
	{

	}

	/* (non-Javadoc)
	 * @see it.unical.canonaco.rende.igpe.game.cbv.guilayer.components.AbstractPainterManager#paintColoredCell(int, int, int, java.awt.Graphics)
	 */
	@Override
	public void paintColoredCell(int row, int column, int tile, float opacity, Color color, Graphics2D graphics) 
	{

	}

	/* (non-Javadoc)
	 * @see it.unical.canonaco.rende.igpe.game.cbv.guilayer.components.AbstractPainterManager#paintTexturedCell(int, int, int, it.unical.canonaco.rende.igpe.game.cbv.logiclayer.engine.component.world.TextureInfoBean)
	 */
	@Override
	public void paintTexturedCell(int row, int column, int tile,TextureInfoBean textureBean, Graphics2D graphics) throws InvalidFileException 
	{
		singleTextureKey.setTextureID(textureBean.getAcutalKey());
		graphics.drawImage(this.spritesCache.getImage(textureSheetKey, 0, true), row*tile,column*tile, null);
	}

	@Override
	public void setting(EventManager eventManager) 
	{
		super.setting(eventManager);
		eventManager.addListener(this, new StartingPositionEvent());
		
	}
	@Override
	public void updateStatus() 
	{
		Iterator<StartingPointGenericPawnsSubjectsInformations> iterator = eventSubjects.values().iterator();
		while(iterator.hasNext())
		{
			iterator.next().action(iterator);
		}
	}
	@Override
	public void paintScene(int tile, Chessboard board, Graphics2D g2d) throws InvalidFileException 
	{
		GenericPawn pawn = null;
		int worldSize = board.getSize();
		overallTextureKey.setFrameKey(spawnareaKey);
		for(int rowIndex = 0; rowIndex < worldSize; rowIndex++)
			{
				for(int columnIndex = 0; columnIndex < worldSize; columnIndex++)
				{
						paintTexturedCell(rowIndex, columnIndex, tile, board.getTexture(rowIndex, columnIndex), g2d);
						if(board.isSpawnable(rowIndex, columnIndex))
						{
							g2d.drawImage(this.spritesCache.getImage(overallTextureKey, 0, true), rowIndex*tile, columnIndex*tile, null);
						}
						pawn = board.getPawn(rowIndex, columnIndex);
					if(pawn != null && !eventSubjects.containsKey(pawn))
					{
						pawnKey.setWho(pawn.getType());
						g2d.drawImage(this.spritesCache.getImage(pawnKey, 0, true), pawn.getRow()*tile, pawn.getColumn()*tile, null);
					}
				}
			}
		
		StartingPointGenericPawnsSubjectsInformations temp = null;
		int x = -1, y = -1;
		Iterator<StartingPointGenericPawnsSubjectsInformations> infoIterator = eventSubjects.values().iterator();
		
		overallTextureKey.setFrameKey(nopeKey);
		for (Point point : nopePoints) 
		{
			g2d.drawImage(this.spritesCache.getImage(overallTextureKey, 0, true), point.x*tile, point.y*tile, null);
		}
		
		while(infoIterator.hasNext())
		{
			temp = infoIterator.next();
			
			if(temp.add)
			{
				x = temp.pawn.getRow();
				y = temp.pawn.getColumn();
			}
			else
			{
				x = temp.eventPoint.x;
				y = temp.eventPoint.y;
			}
			g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, ((float)temp.opacity/100)));
			pawnKey.setWho(temp.pawn.getType());
			g2d.drawImage(this.spritesCache.getImage(pawnKey, 0, true), x*tile, y*tile, null);
		}
		
		
	}
	
	/** */
	@Override
	public void paintClickPoint(int wildX, int wildY, int tile, float opacity,	Graphics2D graphics) throws InvalidFileException 
	{
		graphics.fillRect(wildX*tile, wildY*tile, tile, tile);
	}
	
	/** */
	private static class StartingPointGenericPawnsSubjectsInformations
	{
		private GenericPawn pawn;
		private boolean add;
		private Point eventPoint;
		private int opacity;
		
		private void action(Iterator<StartingPointGenericPawnsSubjectsInformations> iterator)
		{
			if(add)
			{
				if(opacity == 100)
				{
					iterator.remove();
				}
				else
				{
					opacity += 2;
				}
			}
			else
			{
				if(opacity == 0)
				{
					iterator.remove();
				}
				else
				{
					opacity -= 2;
				}
			}
		}
	}
	@Override
	public void coordinates(int wildX, int wildY, int tile, Point storage) 
	{
		storage.x = wildX/tile;
		storage.y = wildY/tile;
	}
	@Override
	public void paintPawn(GenericPawn pawn, int wildX, int wildY, int tile,
			Graphics2D graphics) throws InvalidFileException {
		// TODO Auto-generated method stub
		
	}
	@Override
	public void dispose() {
		super.dispose();
		EventManager.getInstance().removeListener(this, new StartingPositionEvent());
		
	}
}
